﻿using System;
using System.Collections.Generic;
using System.Linq;
using PSE.Deployment.Engine;
using PSE.Deployment.Engine.CustomExceptions;
using PSE.Deployment.Engine.Interfaces;
using PSE.Deployment.SetupBase.Configuration;
using PSE.Deployment.SetupBase.Parameter;
using PSE.Deployment.Util;

namespace PSE.Deployment.SetupBase.Steps
{
    public abstract class SetupStep<TAction> : BaseStep
        where TAction : ActionBase
    {
        private TAction _action;

        protected TAction Action
        {
            get { return _action; }
        }

        private Parameter.Enums.SetupMode _setupMode;

        protected Parameter.Enums.SetupMode SetupMode
        {
            get { return _setupMode; }
        }

        private Group _group;

        protected Group Group
        {
            get { return _group; }
        }

        public SetupStep(IStepGroup parent, Group group, TAction action, Parameter.Enums.SetupMode setupMode)
            : base(parent)
        {
            _action = action;
            _setupMode = setupMode;
            _group = group;

            this.Id = Action.Id;

            if (this.SetupMode == Parameter.Enums.SetupMode.Install)
            {
                this.Description = Action.Description;
                this.ErrorBehavior = PSE.Deployment.Engine.Enums.StepErrorBehavior.NotifyParent;
            }
            else if (this.SetupMode == Parameter.Enums.SetupMode.Uninstall)
            {
                this.ErrorBehavior = PSE.Deployment.Engine.Enums.StepErrorBehavior.Ignore;
                this.Description = string.Format("Desfazendo: {0}", Action.Description);
            }

            this.NavigationBehavior = PSE.Deployment.Engine.Enums.StepNavigationBehavior.NextCancel;
        }

        protected List<InstalledArtefact> GetUsedFiles()
        {
            return (from n in SetupMainFactory.GetInstance().Parameter.InstalledArtefacts
                    from b in n.UsedBy
                    where b.Equals(this.Id)
                    select n).ToList();
        }

        protected void AddUsedBy(string artefactName)
        {
            InstalledArtefact installedFile = null;

            if (SetupMainFactory.GetInstance().Parameter.InstalledArtefacts.Contains(artefactName))
                installedFile = (InstalledArtefact)SetupMainFactory.GetInstance().Parameter.InstalledArtefacts[artefactName];

            if (installedFile == null)
            {
                InstalledArtefact t = new InstalledArtefact();
                t.ArtefactName = artefactName;
                t.UsedBy.Add(new UsedBy(this.Id, this.Action.ToString()));
                SetupMainFactory.GetInstance().Parameter.InstalledArtefacts.Add(t);
            }
            else
            {
                if (installedFile.UsedBy.Find(u => u.Id == this.Id) == null)
                    installedFile.UsedBy.Add(new UsedBy(this.Id, this.Action.ToString()));
            }
        }

        protected void RemoveUsedBy(string artefactName)
        {
            if (SetupMainFactory.GetInstance().Parameter.InstalledArtefacts.Contains(artefactName))
            {
                UsedBy usedBy = SetupMainFactory.GetInstance().Parameter.InstalledArtefacts[artefactName].UsedBy.Find(m => m.Equals(this.Id));

                if (usedBy != null)
                    SetupMainFactory.GetInstance().Parameter.InstalledArtefacts[artefactName].UsedBy.Remove(usedBy);

                if (SetupMainFactory.GetInstance().Parameter.InstalledArtefacts[artefactName].UsedBy.Count == 0)
                    SetupMainFactory.GetInstance().Parameter.InstalledArtefacts.Remove(artefactName);
            }
        }

        protected void UninstallArtefacts()
        {
            MultipleException multipleException = new MultipleException("Ocorreram erros ao remover os arquivos");

            List<InstalledArtefact> artefacts = GetUsedFiles();

            for (int i = artefacts.Count - 1; i >= 0; i--)
            {
                if (this.SetupMode == Parameter.Enums.SetupMode.Uninstall && this.IsStopped())
                    break;

                if (this.SetupMode == Parameter.Enums.SetupMode.Uninstall)
                    this.IncrementProgress(artefacts[i].ArtefactName);
                else
                    this.DecrementProgress(artefacts[i].ArtefactName);

                try
                {
                    if (SetupMainFactory.GetInstance().Parameter.InstalledArtefacts[artefacts[i].ArtefactName].UsedBy.Count(m => m.ActionType == this.Action.ToString()) == 1)
                    {
                        UninstallArtefact(artefacts[i].ArtefactName);
                    }

                    this.RemoveUsedBy(artefacts[i].ArtefactName);
                }
                catch (Exception ex)
                {
                    multipleException.InnerExceptions.Add(ex);
                }
            }

            if (multipleException.InnerExceptions.Count > 0)
                throw multipleException;
        }

        protected virtual void UninstallArtefact(string artefactName)
        {

        }
    }
}